package GA.tournaments;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Random;
import java.io.*;

/**
 * Main class the LUDO simulator - "controlles" the game.
 * This is where you decise how many games to play and if 
 * the graphical interface should be visible.
 * 
 * @author David Johan Christensen
 * 
 * @version 0.9
 */
public class LUDO extends Frame implements ActionListener
{
	private static final long serialVersionUID = 1L;
	public static boolean visual = false;
	//public static boolean visual = true;
	public boolean readChromFile = false; // false = generate chromosomes  true = use file.
	public boolean saveChromFile = true;
	public boolean backup = true;
	public boolean saveFit2d = true; // save all fitness values
	public boolean firstRun = true;
	public int playerColor = 0; // 0 = yellow

	static LUDOBoard board;
	Random intGenerator = new Random(79643);//(25823574);
	int[] result = new int[4];
	int[] gamesWon = new int[4]; 
	public int[] w = {14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
	public static int weightCount = 14;
	public int maxWeightValue = 100;
	public int gamesPerchrom = 10000;
	public int evolutions = 25; // No of generations.
	public static int chromCount = 100; // Amount of chromosomes.
	public static int[][] chromWeights = new int[chromCount][weightCount];
	public int mutateChance = 4;// for each weight: if(rand(4) = 0 -> mutate
	public int tournamentCount = 2; // Number of participants in each tournament.
	public float mutation = (float) 0.06; //0.15; //0.17; // Should be 1/Chromosome length.
	public float crossover = (float) 0.12; //0.15; //0.17; // 0.17 for 6 weights and 0.07 for 14
	public String dataFile = "Ga2Games10000ChangeStart.txt"; // For statistics.
	public String chromFile = "Ga2Val100ch100games1000m3SemiGen25b.txt"; // Save progress: 13 weights of 250 chromosomes
	public String fit2d = "Ga2Val100ch100games1000m3SemiGen25b_allFitnessValues.txt";
	public String chromFileRead = "BackUpGa2Val100ch100bSemiGen25.txt";
	public String fitFile = "BackUpFitGa2Val100ch100bSemiGen25.txt"; // Save progress: 13 weights of 250 chromosomes
	int fileOffset = 0; // Offset if using saved progress and using backup.
	public static int[] permut = {1, 2, 3, 4, 5, 6};//, 7, 8};
	int pWeightCount = permut.length;

	
	public float[] fitness = new float[chromCount]; // Percentage of points gained. 0.5 indicates 100% win of games.
	public float[][] fitness2d = new float[evolutions][chromCount]; // Array to save all fitness values.
	
	int crossoverNo = (int) Math.ceil(chromCount * crossover) ;
	int mutationNo = (int) Math.ceil(chromCount * mutation);
	// Find index for crossover and mutate.
	int crossIndex = chromCount-crossoverNo-mutationNo;
	int mutateIndex = chromCount-mutationNo;

	public LUDO() 
	{  
		super("LUDO Simulator");
		setBackground(Color.white);
		board = new LUDOBoard();
		add(board, BorderLayout.CENTER);
		Menu optionsMenu = new Menu("Options", true);  
		optionsMenu.add("Reset Game");
		optionsMenu.addActionListener(this);
		MenuBar mbar = new MenuBar();  
		mbar.add(optionsMenu);
		setMenuBar(mbar); // Add the menu bar to the frame.
		setBounds(30,50,1000,800);  // Set size and position of window.

		setResizable(false);
		addWindowListener(
				new WindowAdapter() {
					public void windowClosing(WindowEvent evt) {
						LUDO.this.dispose();
						System.exit(0);

					}
				}
		);
		setVisible(visual);

		evolve2();
	}

	public void actionPerformed(ActionEvent event) 
	{
		if(event.getActionCommand()=="Reset Game") {
			board.kill();
		}
	}


	// Play for testing reuse of players.
	public float play4() {
		result[0] = 0; result[1] = 0; result[2] = 0; result[3] = 0; 
		gamesWon[0] = 0; gamesWon[1] = 0; gamesWon[2] = 0; gamesWon[3] = 0;		
		int startPlayer = 0;

		board.setPlayer(new Ga3LUDOPlayer(board),LUDOBoard.YELLOW);
		((Ga3LUDOPlayer)board.yellowPlayer).updateGa(w);

		try {
			for(int i=0;i<gamesPerchrom;i++) {
				board.setStartColor(startPlayer); // change starting player.
				startPlayer++;
				if(startPlayer == 4)
					startPlayer = 0;

				board.play();
				board.kill();

//				result[0]+=board.getPoints()[0];
//				result[1]+=board.getPoints()[1];
//				result[2]+=board.getPoints()[2];
//				result[3]+=board.getPoints()[3];

				// Check who won the game.
				for(int w = 0; w < 4; w++) {
					if(board.getPoints()[w] == 3) {
						gamesWon[w] += 1;
					}
				}

				board.reset();

				board.setPlayer(new Ga3LUDOPlayer(board),LUDOBoard.YELLOW);
				((Ga3LUDOPlayer)board.yellowPlayer).updateGa(w);
				//if((i%500)==0) System.out.print(".");
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
//		int sumS = result[0] + result[1] + result[2] + result[3];
//		float score = (float) result[playerColor] / sumS;
//		return score*2; // Percentage of max points 1 player can get.
		int sum = gamesWon[0] + gamesWon[1] + gamesWon[2] +gamesWon[3];
		float won = (float) gamesWon[playerColor] *100 / sum;  // Change to the player color!!!
		//System.out.println("Wins: " + won);
		return won;
	}
	 

	public void evolve() {
		long time;

		if(readChromFile)
			readChromosomes(chromFileRead);
		else {
			// Create random starting chromosomes, where each weight is unique.
			int newValue;
			int tValue = 1;
			boolean duplicateValue = false;
			for(int row = 0; row < chromCount; row++) {
				for(int col = 0; col < weightCount; col++) {
					do {
						duplicateValue = false; // Reset boolean.
						newValue = intGenerator.nextInt(maxWeightValue)+1;
						for (int i = 0; i < col; i++) {
							tValue = chromWeights[row][i];
							if( tValue == newValue) { // Test if value already exist.
								duplicateValue = true;	
								break;
							}
						}					
					} while (duplicateValue);
					chromWeights[row][col] = newValue;			
				}
			}
			System.out.println(" **** Chromosomes generated **** ");
		}


		// Run specified evolutions;
		for(int i = 1; i <= evolutions; i++) {
			time = System.currentTimeMillis();

			evolveChromosome();

			System.out.print(" Generation: " + i);
			System.out.print(" time: "+(System.currentTimeMillis()-time)+" miliseconds");
			for(int a = 0; a < weightCount; a++ )
				System.out.print(" " + chromWeights[0][a] + ",");
			System.out.println();

			// Backup for every 25th generation.
			if(backup) {
				if(i%25 == 0) {
					String cName = "BackUpw14Val100ch100SemiChangeStartGen" + (i+fileOffset) + ".txt";
					String fName = "BackUpFitw14Val100ch100SemiChangeStartGen" + (i+fileOffset) + ".txt";
					//System.out.println(fName);
					saveChromosomes(cName, chromWeights);
					save1dArray(fName, fitness);					
				}
			}

			// Collect all fitness values into one array for saving to file.
			if(saveFit2d) {
				for(int c = 0; c < chromCount; c++) {
					fitness2d[i-1][c] = fitness[c];
				}
			}
		}

		System.out.println();
		System.out.println(" **** End of evolution **** ");
		System.out.println("Top 5 chromosomes:");
		for(int row = 0; row < 5; row++) {
			for(int c = 0; c < weightCount; c++) {
				System.out.print(" " + chromWeights[row][c] + ",");
			}
			System.out.println();
		}

		if(saveChromFile)
			saveChromosomes(chromFile, chromWeights);
		if(saveFit2d)
			saveFitness2d(fit2d, fitness2d);		

		// Average fitness
		float fit = 0;
		for(int row = 0; row < fitness.length; row++) {
			fit += fitness[row];
		}
		System.out.print("Fitness average: " + fit/fitness.length);
		System.out.println();

		// all fitnes values
		/*		System.out.print("Fitness all values: ");
		for(int row = 0; row < fitness.length; row++) {
			System.out.print(" " + fitness[row]);
		}
		System.out.println();*/
	}

	// Evolve the Gentetic algorithm.
	public void evolveChromosome() {
		//float won = 0; // Percentage of games won

		for(int g = 0; g < chromCount; g++) {
			for(int a = 0; a < weightCount; a++) // update public weights
			{
				w[a] = chromWeights[g][a];				
			}	
			//fitness[g] = play2(); // Get the fitness value for each of the chromosomes.	
			fitness[g] = play4();
		}	

		// Sort chromosomes by fitness
		// Descending selection sort. Using index so values are only moved once.
		int[] wTemp = new int[weightCount];
		for(int i = 0; i < fitness.length-1; i++) {
			int maxIndex = i; // Index of largest remaining value.
			for(int j = i+1; j<fitness.length; j++) {
				if(fitness[maxIndex] < fitness[j]) { // ">" for ascending sort.
					maxIndex = j; // New max value.
				}
			}
			if(maxIndex != i) {		
				// exchange current element with the largest remaining.
				float temp = fitness[i];
				fitness[i] = fitness[maxIndex];
				fitness[maxIndex] = temp;	
				// for loop for all weights
				for(int c = 0; c < weightCount; c++) { // Copy chromosome with the index to the sorted fitness list.
					wTemp[c] = chromWeights[i][c];
					chromWeights[i][c] = chromWeights[maxIndex][c];
					chromWeights[maxIndex][c] = wTemp[c];
				}
			}
		}		
		// End sort.

		//System.out.println();
		System.out.print("Fitness top 5: ");
		for(int row = 0; row < 5; row++) {
			System.out.print((float) fitness[row] + " ");
		}

		// Do crossover - Could state that one should be in the top 40%.
		crossover();

		// Do mutation.
		//mutate();
		//mutate2();
		mutate3();
	}

	public void evolve2() {
		long time;

		if(readChromFile){
			readChromosomes(chromFileRead);
			readFitness(fitFile);
		}
		else {
			// Create random starting chromosomes, where each weight is unique.
			int newValue;
			int tValue = 1;
			boolean duplicateValue = false;
			for(int row = 0; row < chromCount; row++) {
				for(int col = 0; col < weightCount; col++) {
					do {
						duplicateValue = false; // Reset boolean.
						newValue = intGenerator.nextInt(maxWeightValue)+1;
						for (int i = 0; i < col; i++) {
							tValue = chromWeights[row][i];
							if( tValue == newValue) { // Test if value already exist.
								duplicateValue = true;	
								break;
							}
						}					
					} while (duplicateValue);
					chromWeights[row][col] = newValue;			
				}
			}
			System.out.println(" **** Chromosomes generated **** ");
		}


		// Run specified evolutions;
		for(int i = 1; i <= evolutions; i++) {
			time = System.currentTimeMillis();

			evolveChromosome2();

			System.out.print(" Generation: " + i);
			System.out.print(" time: "+(System.currentTimeMillis()-time)+" miliseconds");
			for(int a = 0; a < weightCount; a++ )
				System.out.print(" " + chromWeights[0][a] + ",");
			System.out.println();

			// Backup for every 25th generation.
			if(backup) {
				if(i%25 == 0) {
					String cName = "BackUpGa2Val100ch100bSemiGen" + (i+fileOffset) + ".txt";
					String fName = "BackUpFitGa2Val100ch100bSemiGen" + (i+fileOffset) + ".txt";
					saveChromosomes(cName, chromWeights);
					save1dArray(fName, fitness);					
				}
			}

			// Collect all fitness values into one array for saving to file.
			if(saveFit2d) {
				for(int c = 0; c < chromCount; c++) {
					fitness2d[i-1][c] = fitness[c];
				}
			}
		}

		System.out.println();
		System.out.println(" **** End of evolution **** ");
		System.out.println("Top 5 chromosomes:");
		for(int row = 0; row < 5; row++) {
			for(int c = 0; c < weightCount; c++) {
				System.out.print(" " + chromWeights[row][c] + ",");
			}
			System.out.println();
		}

		if(saveChromFile)
			saveChromosomes(chromFile, chromWeights);
		if(saveFit2d)
			saveFitness2d(fit2d, fitness2d);		

		// Average fitness
		float fit = 0;
		for(int row = 0; row < fitness.length; row++) {
			fit += fitness[row];
		}
		System.out.print("Fitness average: " + fit/fitness.length);
		System.out.println();

		// all fitnes values
		/*		System.out.print("Fitness all values: ");
		for(int row = 0; row < fitness.length; row++) {
			System.out.print(" " + fitness[row]);
		}
		System.out.println();*/
	}
	
	// Evolve the Gentetic algorithm but only play() with new children.
	public void evolveChromosome2() {
		if(firstRun) {
			for(int g = 0; g < chromCount; g++) {
				for(int a = 0; a < weightCount; a++) // update public weights
				{
					w[a] = chromWeights[g][a];				
				}	
				//fitness[g] = play2(); // Get the fitness value for each of the chromosomes.	
				fitness[g] = play4();
			}
			firstRun = false;
		}		
		else{
			for(int g = crossIndex; g < chromCount; g++) {
				for(int a = 0; a < weightCount; a++) // update public weights
				{
					w[a] = chromWeights[g][a];				
				}	
				//fitness[g] = play2(); // Get the fitness value for each of the chromosomes.	
				fitness[g] = play4();
			}			
		}

		// Sort chromosomes by fitness
		// Descending selection sort. Using index so values are only moved once.
		int[] wTemp = new int[weightCount];
		for(int i = 0; i < fitness.length-1; i++) {
			int maxIndex = i; // Index of largest remaining value.
			for(int j = i+1; j<fitness.length; j++) {
				if(fitness[maxIndex] < fitness[j]) { // ">" for ascending sort.
					maxIndex = j; // New max value.
				}
			}
			if(maxIndex != i) {		
				// exchange current element with the largest remaining.
				float temp = fitness[i];
				fitness[i] = fitness[maxIndex];
				fitness[maxIndex] = temp;	
				// for loop for all weights
				for(int c = 0; c < weightCount; c++) { // Copy chromosome with the index to the sorted fitness list.
					wTemp[c] = chromWeights[i][c];
					chromWeights[i][c] = chromWeights[maxIndex][c];
					chromWeights[maxIndex][c] = wTemp[c];
				}
			}
		}		
		// End sort.

		//System.out.println();
		System.out.print("Fitness top 5: ");
		for(int row = 0; row < 5; row++) {
			System.out.print((float) fitness[row] + " ");
		}

		// Do crossover - Could state that one should be in the top 40%.
		crossover();

		// Do mutation.
		//mutate();
		//mutate2();
		mutate3();
	}



	// Test for statistics with permutation -create all possible combinations of e.g. 6 weights
	public void testPermute() {
		//float[][] fitnessValues = new float[evolutions][chromCount];
		// Create starting chromosomes, by finding all unique combinations of the values in permut[].
		permute(permut, 0, pWeightCount-1);
		System.out.println(" **** Chromosomes generated **** ");
		long time;

		// Run each chromosome.
		time = System.currentTimeMillis();
		for(int g = 0; g < chromCount; g++) {
			for(int a = 0; a < weightCount; a++) { // Update public weights.
				w[a] = chromWeights[g][a];				
			}	
			//fitness[g] = play2(); // Get the fitness value for each of the chromosomes.
			fitness[g] = play4();
			System.out.println("Chromosome: " + (g+1));
		}	
		System.out.println(" Time: " + (System.currentTimeMillis()-time)+" ms");

		// Save unsorted data + fitness.
		System.out.println("Saving data...");
		saveDataFitness("b6unsort5000games_YellowPl_Ystart.txt", chromWeights, fitness);
		//saveDataFitness("b6unsortTest.txt", chromWeights, fitness);
		System.out.println("Unsorted chromosomes saved");

		// Sort chromosomes by fitness.
		// Descending selection sort. Using index so values are only moved once.
		//int[] wTemp = new int[pWeightCount];
		int maxIndex, wTemp, j, c;
		float temp;
		for(int i = 0; i < fitness.length-1; i++) {
			maxIndex = i; // Index of largest remaining value.
			for(j = i+1; j<fitness.length; j++) {
				if(fitness[maxIndex] < fitness[j]) { // ">" for ascending sort.
					maxIndex = j; // New max value.
				}
			}
			if(maxIndex != i) {		
				// exchange current element with the largest remaining.
				temp = fitness[i];
				fitness[i] = fitness[maxIndex];
				fitness[maxIndex] = temp;	
				// for loop for all weights
				for(c = 0; c < pWeightCount; c++) { // Copy chromosome with the index to the sorted fitness list.
					wTemp = chromWeights[i][c];//wTemp[c] = chromWeights[i][c];
					chromWeights[i][c] = chromWeights[maxIndex][c];
					chromWeights[maxIndex][c] = wTemp; //wTemp[c];
				}
			}
		}		
		// End sort.

		// Save sorted data and fitness.
		System.out.println("Saving sorted data...");
		saveDataFitness("b6sorted5000games_YellowPl_Ystart.txt", chromWeights, fitness);
		//saveDataFitness("b6sortedTest.txt", chromWeights, fitness);
		System.out.println("Sorted chromosomes saved");
	}



	// Permutation. Create all possible unique combinations of chromosomes using recursive calls to itself.
	static int pRow = 0;
	public static void permute(int[] list, int k, int m) { // Generate all permutations of list[k:m].
		int i, temp;
		if(k==m) { // list[k:m] has one permutation, output it.
			for(i=0; i<=m; i++) {
				//System.out.print(list[i]);
				chromWeights[pRow][i] = list[i];
			}
			//System.out.println();
			pRow++;
		}
		else {// list[k:m] has more than one permutation, generate these recursively.
			for(i=k; i<=m; i++) {
				// Swap the two elements.
				temp = list[k];
				list[k] = list[i];
				list[i] = temp;

				permute(list, k+1, m);

				// Swap back.
				temp = list[k];
				list[k] = list[i];
				list[i] = temp;
			}
		}
	}


	public static int factorial(int n) {
		int temp = 1;
		int i;
		if (n > 1) {
			for (i = 1; i <= n; i++) {
				temp *= i;
			}
		}
		return temp;
	}

	// Do tournament selection of given size between the chromosomes that are being kept for next round.
	// Return index of chosen member.
	public int tournament(int tSize) {
		int i, j;
		int k = -1;
		float bestFit = (float) 0.0;
		int bestMember = 0;

		for(i=0; i<tSize; i++) {
			do{
				j = intGenerator.nextInt(crossIndex);
			} while (j==k);
			k=j;

			if( bestFit < fitness[j]) { //if(fitness[j] < bestFit) {
				bestFit = fitness[j];
				bestMember = j;
			}
		}
		return(bestMember);
	}

	// Combine two chromosomes.
	public void crossover() {
		int g1, g2;
		int breakingPoint;
		for(int cr = crossIndex; cr < mutateIndex; cr++ ) {
			g1 = tournament(tournamentCount); // Find index of first chromosome, by taking the best of (x) random chromosomes.
			do {
				g2 = tournament(tournamentCount);
			} while(g1 == g2); // Make sure the chromosomes are different.

			breakingPoint = intGenerator.nextInt(weightCount-2)+1; // Find a point which is not the first nor the last index.
			for(int i = 0 ; i < weightCount; i++ ) {
				if(i < breakingPoint) {
					chromWeights[cr][i] = chromWeights[g1][i];
				}
				else
					chromWeights[cr][i] = chromWeights[g2][i];
			}		
		}
	}

	// Mutate a chromosome, by setting a random weight to a random value.
	public void mutate() {
		int mg; // Index of chromosome to mutate
		int h = -1;
		int mutatePoint = 0;
		int mutateValue = 1;
		for(int mu = mutateIndex; mu < chromCount; mu++ ) { // For all the allocated chromosome mutations.
			// Next do-while part is a hack to make sure that it pick a new chromosome instead of getting the same random int. 
			do{
				mg = intGenerator.nextInt(crossIndex); // Pick a random chromosome.
			} while (mg==h);
			h=mg;

			for(int i = 0; i < weightCount; i++) {
				chromWeights[mu][i] = chromWeights[mg][i]; // Copy chromosome to mutate.
			}
			mutatePoint = intGenerator.nextInt(weightCount);
			//chromWeights[mu][mutatePoint] = intGenerator.nextInt(maxWeightValue)+1; // Mutate.
			do {
				mutateValue = intGenerator.nextInt(maxWeightValue)+1; // Mutate.
			} while (mutateValue == (chromWeights[mu][mutatePoint]) );  // Make sure that the value is different from the original.
			chromWeights[mu][mutatePoint] = mutateValue;
		}
	}

	// Mutate a chromosome, by applying a chance for each weight to get a random value.
	public void mutate2() {
		int mg; // Index of chromosome to mutate
		int h = -1;
		for(int mu = mutateIndex; mu < chromCount; mu++ ) { // For all the allocated chromosome mutations.
			// Next do-while part is a hack to make sure that it pick a new chromosome instead of getting the same random int. 
			do{
				mg = intGenerator.nextInt(crossIndex); // Pick a random chromosome.
			} while (mg==h);
			h=mg;

			for(int i = 0; i < weightCount; i++) {
				chromWeights[mu][i] = chromWeights[mg][i]; // Copy chromosome to mutate.
			}
			for(int wi = 0; wi < weightCount; wi++) {
				if(intGenerator.nextInt(mutateChance)==0)
					chromWeights[mu][wi] = intGenerator.nextInt(maxWeightValue)+1; // Mutate.
			}
		}
	}

	// Mutate chromosome, by first taking one chromosome and change one weight and second
	// take another chromosome where each weight is applied a chance for each weight to get a random value.
	// This is repeated until all the mutations are done.
	public void mutate3() {
		int mg; // Index of chromosome to mutate
		int h = -1;
		Boolean select = true; // Used to toggle mutate methods.
		int mutatePoint = 0;
		int mutateValue = 1;
		for(int mu = mutateIndex; mu < chromCount; mu++ ) { // For all the allocated chromosome mutations.
			// Next do-while part is a hack to make sure that it pick a new chromosome instead of getting the same random int. 
			do{
				mg = intGenerator.nextInt(crossIndex); // Pick a random chromosome.
			} while (mg==h);
			h=mg;

			for(int i = 0; i < weightCount; i++) {
				chromWeights[mu][i] = chromWeights[mg][i]; // Copy chromosome to mutate.
			}
			if(select) {
				mutatePoint = intGenerator.nextInt(weightCount);
				do {
					mutateValue = intGenerator.nextInt(maxWeightValue)+1; // Mutate.
				} while (mutateValue == (chromWeights[mu][mutatePoint]) );  // Make sure that the value is different from the original.
				chromWeights[mu][mutatePoint] = mutateValue;
				select = false;
			}
			else {
				for(int wi = 0; wi < weightCount; wi++) {
					if(intGenerator.nextInt(mutateChance)==0)
						chromWeights[mu][wi] = intGenerator.nextInt(maxWeightValue)+1; // Mutate.
				}
				select = true;
			}
		}
	}

	// Save [][] array of to a file.
	public void saveFitness2d(String filename, float[][] dataOut) {
		try {
			/*			FileOutputStream fos = new FileOutputStream(filename);
			GZIPOutputStream gzos = new GZIPOutputStream(fos);
			ObjectOutputStream out = new ObjectOutputStream(gzos);
			out.writeObject(dataOut);
			out.flush();
			out.close();	*/	
			FileWriter fw = new FileWriter(filename);
			BufferedWriter bw = new BufferedWriter(fw);
			PrintWriter outFile = new PrintWriter(bw);

			for(int row = 0; row < evolutions; row++) {
				for(int col = 0; col < chromCount; col++) {
					outFile.print(dataOut[row][col] + "; ");
					//System.out.print(dataOut[row][col] + " ");
				}
				outFile.println();
				//System.out.println();
			}
			outFile.close();
		}
		catch (IOException e) {
			System.out.println(e);
		}
		System.out.println("2d data saved");		
	}

	// Save 1D array of fitness values to a file.
	public void save1dArray(String filename, float[] dataOut) {
		try {
			FileWriter fw = new FileWriter(filename);
			BufferedWriter bw = new BufferedWriter(fw);
			PrintWriter outFile = new PrintWriter(bw);

			for(int c = 0; c < dataOut.length; c++) {
				outFile.print(dataOut[c]);// + "; ");
				outFile.println();
				//System.out.print(dataOut[row][col] + " ");
			}
			outFile.close();
		}
		catch (IOException e) {
			System.out.println(e);
		}
		//System.out.println("Data saved");		
	}

	// Save array of permutations to a file.
	public void saveDataFitness(String filename, int[][] chromsOut, float[] fitness) {
		try {
			FileWriter fw = new FileWriter(filename);
			BufferedWriter bw = new BufferedWriter(fw);
			PrintWriter outFile = new PrintWriter(bw);

			for(int row = 0; row < chromCount; row++) {
				for(int col = 0; col < pWeightCount; col++) {
					outFile.print(chromsOut[row][col] + "; ");
				}
				outFile.print(fitness[row] + "; ");
				outFile.println();
			}
			outFile.close();
		}
		catch (IOException e) {
			System.out.println(e);
		}		
	}

	// Save array of chromosomes to a file.
	public void saveChromosomes(String filename, int[][] dataOut) {
		try {
			FileWriter fw = new FileWriter(filename);
			BufferedWriter bw = new BufferedWriter(fw);
			PrintWriter outFile = new PrintWriter(bw);

			for(int row = 0; row < chromCount; row++) {
				for(int col = 0; col < weightCount; col++) {
					outFile.print(dataOut[row][col] + " ");
					//System.out.print(dataOut[row][col] + " ");
				}
				outFile.println();
				//System.out.println();
			}
			outFile.close();
		}
		catch (IOException e) {
			System.out.println(e);
		}
		System.out.println("Chromosomes saved");		
	}

	// Read array of chromosomes from a file.
	public void readChromosomes(String filename) {
		try {
			int r = 0;
			int c = 0;
			//create a buffered reader and hook it to our file
			BufferedReader br = new BufferedReader(new FileReader(filename));

			//to read a whole line use readLine()

			//to scan through the whole file line by line, do this.			 
			String line = br.readLine();  //priming read
			while(line != null)
			{
				//line = br.readLine();
				String[] theLine = line.split(" ");

				try {
					for(String w:theLine) {
						chromWeights[r][c] = Integer.parseInt(w);					
						c++;
					}				
				}	
				/*String [] entries = line.split(",");

				int currEntry;
				try
				{
					currEntry = Integer.parseInt(entries[0]);
				}*/
				catch(NumberFormatException nfe)
				{
					System.out.println("Invalid number");
				}
				r++;
				c = 0;
				line = br.readLine();
			}
		}
		catch (IOException e) {
			System.out.println(e);
		}
		System.out.println("Chromosomes read");
	}
	
	// Read array of fitness values from a file. -copy of readChromosomes
	public void readFitness(String filename) {
		try {
			int r = 0;
			//create a buffered reader and hook it to our file
			BufferedReader br = new BufferedReader(new FileReader(filename));

			//to scan through the whole file line by line, do this.			 
			String line = br.readLine();  //priming read
			while(line != null)
			{
				//line = br.readLine();
				String[] theLine = line.split(" ");
				try {
					for(String w:theLine) {
						fitness[r] = Float.parseFloat(w);// Integer.parseInt(w);
					}				
				}	
				catch(NumberFormatException nfe)
				{
					System.out.println("Invalid number");
				}
				r++;
				line = br.readLine();
			}
		}
		catch (IOException e) {
			System.out.println(e);
		}
		System.out.println("Fitness values read");
	}


	// test of reading from chromFile
	public void testRead() {
		readChromosomes(chromFile);

		for(int row = 0; row < chromCount; row++) {
			for(int col = 0; col < weightCount; col++) {
				System.out.print(chromWeights[row][col] + " ");
			}
			System.out.println();
		}
	}

	public static void main(String[] args)
	{
		new LUDO();
	}
}

// To test dice -insert below in LUDOBOard line 296
/*// Hijack dice
int[] diceRolls = new int[6];
int d;
for(long i = 0; i < 10000; i++) {
	d = Math.abs(rand.nextInt())%6+1;
	diceRolls[d-1] = (diceRolls[d-1])+1;
}
System.out.println("Dice: " + diceRolls[0] + " " + diceRolls[1] + " " + diceRolls[2] + " " + diceRolls[3] + " " + diceRolls[4] + " " + diceRolls[5]);
// end
 * */
